﻿using System;
using System.Globalization;
using System.IO;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using UFIDA.U9.Cust.Pub.WS.ProxyService.Json;
using UFIDA.U9.WSS.ProxyService.Exceptions;
using UFIDA.U9.WSS.ProxyService.Utils;
using UFSoft.UBF.Util.Log;

namespace UFIDA.U9.WSS.ProxyService.Json
{
    /// <summary>
    ///     Json 帮助类
    /// </summary>
    public static class JsonHelper
    {
        private const string DefaultDateTimeFormat = "yyyy-MM-dd HH:mm:ss";
        private const DateTimeStyles DefaultDateTimeStyles = DateTimeStyles.AssumeLocal;
        private const Formatting DefaulResponeJsonFormatting = Formatting.None;
        private static readonly ILogger Logger = LoggerManager.GetLogger("JsonHelper");

        /// <summary>
        ///     获取Json序列化配置
        /// </summary>
        /// <returns></returns>
        public static JsonSerializerSettings GetJsonSerializerSettings(IContractResolver resolver)
        {
            JsonSerializerSettings settings = new JsonSerializerSettings();
            settings.ContractResolver = resolver;
            settings.MissingMemberHandling = MissingMemberHandling.Ignore;
            settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            string dateTimeFormat = ConfigurationHelper.GetAppSettingValue(Constant.DateTimeFormatName);
            DateTimeStyles dateTimeStyles = DefaultDateTimeStyles;
            string strDateTimeStyles = ConfigurationHelper.GetAppSettingValue(Constant.DateTimeStylesName);
            if (!string.IsNullOrEmpty(strDateTimeStyles))
                Enum.TryParse(strDateTimeStyles, out dateTimeStyles);
            settings.Converters.Add(new CustIsoDateTimeConverter
            {
                DateTimeFormat = string.IsNullOrEmpty(dateTimeFormat) ? DefaultDateTimeFormat : dateTimeFormat,
                DateTimeStyles = dateTimeStyles
            });
            settings.Converters.Add(new DataSetConverter());
            settings.Converters.Add(new DataTableConverter());
            return settings;
        }

        /// <summary>
        ///     获取JsonSerializer
        /// </summary>
        /// <param name="resolver"></param>
        /// <returns></returns>
        public static JsonSerializer GetJsonSerializer(IContractResolver resolver)
        {
            JsonSerializer serializer = new JsonSerializer();
            serializer.ContractResolver = resolver;
            serializer.MissingMemberHandling = MissingMemberHandling.Ignore;
            serializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
            string dateTimeFormat = ConfigurationHelper.GetAppSettingValue(Constant.DateTimeFormatName);
            DateTimeStyles dateTimeStyles = DefaultDateTimeStyles;
            string strDateTimeStyles = ConfigurationHelper.GetAppSettingValue(Constant.DateTimeStylesName);
            if (!string.IsNullOrEmpty(strDateTimeStyles))
                Enum.TryParse(strDateTimeStyles, out dateTimeStyles);
            serializer.Converters.Add(new CustIsoDateTimeConverter
            {
                DateTimeFormat = string.IsNullOrEmpty(dateTimeFormat) ? DefaultDateTimeFormat : dateTimeFormat,
                DateTimeStyles = dateTimeStyles
            });
            serializer.Converters.Add(new DataSetConverter());
            serializer.Converters.Add(new DataTableConverter());
            return serializer;
        }

        /// <summary>
        ///     获取默认JsonSerializer
        /// </summary>
        /// <returns></returns>
        public static JsonSerializer GetDefaultJsonSerializer()
        {
            return GetJsonSerializer(new BaseContractResolver());
        }

        /// <summary>
        ///     获取返回JsonBody
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="resolver"></param>
        /// <returns></returns>
        public static byte[] GetReturnJsonBody(object obj, IContractResolver resolver = null)
        {
            byte[] body;
            if (resolver == null)
                resolver = new BaseContractResolver();
            JsonSerializer serializer = GetJsonSerializer(resolver);
            string strReturnJsonNoStartsWithBOM =
                ConfigurationHelper.GetAppSettingValue(Constant.ResponeJsonNoStartsWithBOMName);
            bool returnJsonNoStartsWithBOM = !string.IsNullOrEmpty(strReturnJsonNoStartsWithBOM) &&
                                             strReturnJsonNoStartsWithBOM.ToLower() == "true";
            string returnJsonFormatting =
                ConfigurationHelper.GetAppSettingValue(Constant.ResponeJsonFormattingName);
            using (MemoryStream ms = new MemoryStream())
            {
                using (StreamWriter sw = new StreamWriter(ms, new UTF8Encoding(returnJsonNoStartsWithBOM)))
                {
                    using (JsonWriter writer = new JsonTextWriter(sw))
                    {
                        writer.Formatting = !string.IsNullOrEmpty(returnJsonFormatting) &&
                                            returnJsonFormatting.ToLower() == "indented"
                            ? Formatting.Indented
                            : DefaulResponeJsonFormatting;
                        serializer.Serialize(writer, obj);
                        sw.Flush();
                        body = ms.ToArray();
                        writer.Close();
                    }

                    sw.Close();
                }

                ms.Close();
            }

            return body;
        }

        /// <summary>
        ///     获取Json某个属性的值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="rawBody"></param>
        /// <param name="propertyName"></param>
        /// <param name="resolver"></param>
        /// <returns></returns>
        public static T GetJsonPropertyValue<T>(byte[] rawBody, string propertyName, IContractResolver resolver = null)
            where T : class
        {
            object propertyValue = GetJsonPropertyValue(rawBody, typeof(T), propertyName, resolver);
            return propertyValue == null ? default(T) : propertyValue as T;
        }

        /// <summary>
        ///     获取Json某个属性的值
        /// </summary>
        /// <param name="rawBody"></param>
        /// <param name="propertyType"></param>
        /// <param name="propertyName"></param>
        /// <param name="resolver"></param>
        /// <returns></returns>
        public static object GetJsonPropertyValue(byte[] rawBody, Type propertyType, string propertyName,
            IContractResolver resolver = null)
        {
            string propertyNameLower = propertyName.ToLower();
            using (MemoryStream ms = new MemoryStream(rawBody))
            {
                using (StreamReader sr = new StreamReader(ms))
                {
                    JsonReader reader = new JsonTextReader(sr);
                    reader.Read();
                    if (reader.TokenType != JsonToken.StartObject)
                    {
                        throw new WSException(ExceptionCodes.ServiceRequestDataFormatException,
                            "input needs to be wrapped in an object");
                    }

                    reader.Read();
                    while (reader.TokenType == JsonToken.PropertyName)
                    {
                        string parameterName = reader.Value as string;
                        string parameterNameLower =
                            string.IsNullOrEmpty(parameterName) ? string.Empty : parameterName.ToLower();
                        reader.Read();
                        if (parameterNameLower == propertyNameLower)
                        {
                            try
                            {
                                if (resolver == null)
                                    resolver = new BaseContractResolver();
                                //如果类型是object,且json是字符串，直接采用字符串反序列化
                                if (reader.TokenType == JsonToken.String && !propertyType.IsValueType &&
                                    !propertyType.IsPrimitive
                                    && typeof(string) != propertyType && propertyType.IsSubclassOf(typeof(object)))
                                {
                                    JsonSerializerSettings settings = GetJsonSerializerSettings(resolver);
                                    return JsonConvert.DeserializeObject(reader.Value as string, propertyType,
                                        settings);
                                }

                                JsonSerializer serializer = GetJsonSerializer(resolver);
                                return serializer.Deserialize(reader, propertyType);
                            }
                            catch (Exception ex)
                            {
                                Logger.Error(ex);
                                throw new WSException(ExceptionCodes.ServiceRequestDataFormatException,
                                    string.Format("{0} property is incorrect", parameterName), ex);
                            }
                        }

                        reader.Skip();
                        reader.Read();
                    }

                    reader.Close();
                    sr.Close();
                    ms.Close();
                }
            }

            return null;
        }

        /// <summary>
        ///     对象转为Json
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="resolver"></param>
        /// <returns></returns>
        public static string ToJson(object obj, IContractResolver resolver = null)
        {
            if (obj == null) return string.Empty;
            if (resolver == null)
                resolver = new BaseContractResolver();
            JsonSerializerSettings settings = GetJsonSerializerSettings(resolver);
            return JsonConvert.SerializeObject(obj, Formatting.None, settings);
        }

        /// <summary>
        ///     Json转为对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="jsonString"></param>
        /// <param name="resolver"></param>
        /// <returns></returns>
        public static T FromJson<T>(string jsonString, IContractResolver resolver = null)
        {
            if (resolver == null)
                resolver = new BaseContractResolver();
            JsonSerializerSettings settings = GetJsonSerializerSettings(resolver);
            return JsonConvert.DeserializeObject<T>(jsonString, settings);
        }
    }
}